package cn.wizzer.framework.base.service;

import cn.wizzer.framework.page.Pagination;
import cn.wizzer.framework.util.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.nutz.dao.Cnd;
import org.nutz.dao.Condition;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Record;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 公共方法
 */
@IocBean
public class CommonDBService {

    @Inject
    private Dao dao;

    private static final Log log = Logs.get();

    /**
     * @param t          实体
     * @param pageNumber 第几页
     * @param pageSize   几条
     * @param sql        SQL语句
     * @param <T>
     * @return
     */
    public <T> Pagination listPage(Class<?> t, Integer pageNumber, int pageSize, String sql) {
        Pagination pagination = new Pagination();
        String countStr = " select count(1) count from (" + sql + ") t_v";
        Sql query = Sqls.queryRecord(countStr);
        dao.execute(query);
        List<Record> list = query.getList(Record.class);
        if (list != null && list.size() > 0) {
            int count = list.get(0).getInt("count");
            Pager pager = new Pager();
            pager.setPageNumber(pageNumber);
            pager.setPageSize(pageSize);
            /**查询记录*/
            query = Sqls.queryRecord(sql);
            query.setPager(pager);
            dao.execute(query);
            list = query.getList(Record.class);
            Object obj = null;
            List<T> pageList = new ArrayList<T>();
            for (Record re : list) {
                obj =JSON.parseObject(JSONObject.toJSONString(re),t);
                pageList.add((T) obj);
            }
            pagination.setList(pageList);
            pagination.setPageNo(pageNumber);
            pagination.setPageSize(pageSize);
            pagination.setTotalCount(count);//手动赋值
        }
        return pagination;
    }

    /**
     * @param t          实体
     * @param pageNumber 第几页
     * @param pageSize   几条
     * @param sql        SQL语句
     * @param <T>
     * @return
     */
    public <T> Pagination listPage(Class<?> t, Integer pageNumber, int pageSize, String sql, String countSql) {
        /**查总数**/
        Sql query = Sqls.fetchInt(countSql);
        dao.execute(query);
        int count = query.getInt();
        Pager pager = new Pager();
        pager.setPageNumber(pageNumber);
        pager.setPageSize(pageSize);
        /**查询记录*/
        query = Sqls.queryRecord(sql);
        query.setPager(pager);
        dao.execute(query);
        List<Record> list = query.getList(Record.class);
        Object obj;
        List<T> pageList = new ArrayList<T>();
        for (Record re : list) {
            obj =JSON.parseObject(JSONObject.toJSONString(re),t);
            pageList.add((T) obj);
        }
        Pagination pagination = new Pagination();
        pagination.setList(pageList);
        pagination.setPageNo(pageNumber);
        pagination.setPageSize(pageSize);
        pagination.setTotalCount(count);//手动赋值
        return pagination;
    }

    /**
     *
     * @param t
     * @param pageNumber
     * @param pageSize
     * @param sql
     * @param <T>
     * @return
     */
    public <T> Pagination listPageOne2More(Class<T> t, Integer pageNumber, int pageSize, String sql) {
        Pagination pagination = new Pagination();
        String countStr = " select count(1) count from (" + sql + ") t_v";
        Sql query = Sqls.queryRecord(countStr);
        dao.execute(query);
        final List<Record>[] list = new List[]{query.getList(Record.class)};
        if (list[0] != null && list[0].size() > 0) {
            int count = list[0].get(0).getInt("count");
            Pager pager = new Pager();
            pager.setPageNumber(pageNumber);
            pager.setPageSize(pageSize);
            /**查询记录*/
            query = Sqls.queryRecord(sql);
            query.setPager(pager);
            dao.execute(query);
            list[0] = query.getList(Record.class);
            Object obj = null;
            //用以查询主表字段
            Map<String,JSONObject> idMap = new HashMap<>(list[0].size());
            for (Record record : list[0]) {
                if (!idMap.containsKey(record.getString("id"))) {
                    idMap.put(record.getString("id"),JSONUtil.toJSON((JSONObject) JSONUtil.toJSON(record)));
                }
            }
            //去重集
            Stream<String> idStream = list[0].stream()
                    .map(o -> (JSONObject) JSONUtil.toJSON(o))
                    .map(json -> json.getString("id"))
                    .distinct();
            //映射结果
            List<T> pageList = idStream.map(id->{
                //对应ID下的集
                List<JSONObject> resultsById = list[0].stream()
                        .map(o -> (JSONObject) JSONUtil.toJSON(o))
                        .filter(json->id.equals(json.getString("id")))
                        .collect(Collectors.toList());
                //结果
                JSONObject result = idMap.get(id);
                //关联表映射
                for (int i = 0; i < resultsById.size(); i++) {
                    int finalI = i;
                    //设置二级
                    result.keySet().stream()
                            //过滤一级字段
                            .filter(property->property.contains("."))
                            .collect(Collectors.toList())
                            .forEach(specialProperty->{
                                //list名称
                                String firstKey = specialProperty.split("\\.")[0];
                                //list下实体中属性名称
                                String secondKey = specialProperty.split("\\.")[1];
                                if (result.getJSONArray(firstKey)==null){
                                    result.put(firstKey,new JSONArray());
                                    result.getJSONArray(firstKey).add(new JSONObject());
                                }else if (result.getJSONArray(firstKey).size() <= finalI) {
                                    result.getJSONArray(firstKey).add(new JSONObject());
                                }
                                //字段映射到实体
                                Object value = resultsById.get(finalI).get(specialProperty);
                                result.getJSONArray(firstKey).getJSONObject(finalI).put(secondKey, value);
                            });

                }

                //操作结束去除结果集中已使用数据
//                list[0] = list[0].stream().filter(json->json.getString("id").equals(id)).collect(Collectors.toList());
                return JSONUtil.toJavaBean(t,result);
            }).collect(Collectors.toList());
            //分页结果
            pagination.setList(pageList);
            pagination.setPageNo(pageNumber);
            pagination.setPageSize(pageSize);
            pagination.setTotalCount(count);//手动赋值
        }
        return pagination;
    }


    /**
     * 根据CND，获取所需 LIST
     *
     * @param t
     * @param cnd
     * @param <T>
     * @return
     */
    public <T> List<T> list(Class<?> t, Cnd cnd) {
        return (List<T>) dao.query(t, cnd);
    }


    /**
     * 根据SQL语句，获取所需 LIST
     *
     * @param t
     * @param sql
     * @param <T>
     * @return
     */
    public <T> List<T> list(Class<?> t, String sql) {
        Sql query = Sqls.queryRecord(sql);
        dao.execute(query);
        List<Record> list = query.getList(Record.class);
        List<T> reultList = new ArrayList<T>();
        if (list != null && list.size() > 0) {
            Object obj = null;
            for (Record re : list) {
                obj =JSON.parseObject(JSONObject.toJSONString(re),t);
                reultList.add((T) obj);
            }
        }
        return reultList;
    }

    /**
     * 单表查询 返回一个表对应的bean的对象
     *
     * @param t
     * @param c
     * @param <T>
     * @return
     */
    public <T> T fetchCnd(Class<T> t, Condition c) {
        List<T> list = dao.query(t, c);
        if (list != null && list.size() == 1) {
            return list.get(0);
        }
        return null;
    }

    /**
     * 多表关联查询VO
     *
     * @param t
     * @param sql
     * @param <T>
     * @return
     */
    public <T> T fetchSql(Class<T> t, String sql) {
        Sql query = Sqls.queryRecord(sql);
        dao.execute(query);
        List<Record> list = query.getList(Record.class);
        if (list != null && list.size() > 0) {
            Object obj = null;
            for (Record re : list) {
                obj =JSON.parseObject(JSONObject.toJSONString(re),t);
                return (T) obj;
            }
        }
        return null;
    }

    /**
     * 根据sql语句获取集合条数
     *
     * @param sql
     * @return
     */
    public int count(String sql) {
        Sql query = Sqls.queryRecord(sql);
        dao.execute(query);
        return query.getList(Record.class).size();
    }

}
